package br.unb.core.synchronism;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Synchronism {

    public enum Precision {

        /**Value for a HIGH Precision synchronim, (SLOW synchronization)*/
        HIGH(240),
        /**Value for a MEDIUM Precision synchronim, (NORMAL synchronization)*/
        MEDIUM(120),
        /**Value for a LOW Precision synchronim, (FAST synchronization)*/
        LOW(60);
        private final int value;

        private Precision(int p) {
            this.value = p;
        }

        public static Precision init(int i) {
            if (i >= HIGH.value) {
                return HIGH;
            } else if (i >= MEDIUM.value) {
                return MEDIUM;
            } else {
                return LOW;
            }
        }
    }
    Precision precision;
    /***/
    private String syncManagerIp;
    private String clientIp;
    private String serverIp;
    private int port;
    private int offset;

    /**
     * Used on SyncManger to create a syncModel request 
     */
    public Synchronism(String clientIp, String serverIp, int port, Precision precision) {
        this.syncManagerIp = getManagerIP();
        this.clientIp = clientIp;
        this.serverIp = serverIp;
        this.port = port;
        this.precision = precision;
        this.offset = 0;
    }

    //toString Will be needed below
    @Override
    public String toString() {
        //Example string format
        //Manager(Server,Client:Port)=Precision!Offset;
        //127.0.0.1(127.0.0.1,127.0.0.1:8080)240!12344;");

        return (this.syncManagerIp
                + "(" + this.clientIp
                + "," + this.serverIp
                + ":" + port
                + ")" + this.precision.value
                + "!" + this.offset
                + ";us");
    }

    /**
     * Used on the server and the client to decode the request from a string
     * TODO validate string before assign values to atributes!!
     */
    public Synchronism(String syncModel) {
        //Example string format
        //Manager(Server,Client:Port)=Precision!Offset;
        //127.0.0.1(127.0.0.1,127.0.0.1:8080)240!12344;");
        if (syncModel != null) {
            int indexParRight = syncModel.indexOf("("),
                    indexComma = syncModel.indexOf(","),
                    indexDots = syncModel.indexOf(":"),
                    indexParLeft = syncModel.indexOf(")"),
                    //indexEquals = syncModel.indexOf("="),
                    indexOffset = syncModel.indexOf("!"),
                    indexSemiComma = syncModel.indexOf(";");

            //Manager(
            this.syncManagerIp = syncModel.substring(0, indexParRight);
            //(Client,
            this.clientIp = syncModel.substring(indexParRight + 1, indexComma);
            //,Server:
            this.serverIp = syncModel.substring(indexComma + 1, indexDots);
            //:Port)
            String strPort = syncModel.substring(indexDots + 1, indexParLeft);
            int sport = Integer.parseInt(strPort);
            if (sport < 1025) {
                sport = 8080;
            }
            this.port = sport;
            //)Precision!
            String strPrecision = syncModel.substring(indexParLeft + 1, indexOffset);
            int sprecision = Integer.parseInt(strPrecision);
            this.precision = Precision.init(sprecision);//garanties that the precision will be in a desired range
            //!Offset;
            String strOffset = syncModel.substring(indexOffset + 1, indexSemiComma);
            this.offset = Integer.parseInt(strOffset);
        }
    }

    /*
     * Used to get the manager local address
     * (review, since a computer can have many interfaces)
     */
    private String getManagerIP() {
        String manager;
        try {
            manager = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException ex) {
            manager = "0.0.0.0";
        }
        return manager;
    }

    public String getSyncManagerIp() {
        return syncManagerIp;
    }

    public void setSyncManagerIp(String type) {
        this.syncManagerIp = type;
    }

    public InetAddress getSyncManagerIpAddress() throws UnknownHostException {
        InetAddress syncManagerIpAddress = InetAddress.getByName(this.syncManagerIp);
        return syncManagerIpAddress;
    }

    public String getClientIp() {
        return clientIp;
    }

    public void setClientIp(String clientIp) {
        this.clientIp = clientIp;
    }

    public InetAddress getClientIpAddress() throws UnknownHostException {
        InetAddress clientIpAddress = InetAddress.getByName(this.clientIp);
        return clientIpAddress;
    }

    public String getServerIp() {
        return serverIp;
    }

    public void setServerIp(String serverIp) {
        this.serverIp = serverIp;
    }

    public InetAddress getServerIpAddress() throws UnknownHostException {
        InetAddress serverIpAddress = InetAddress.getByName(this.serverIp);
        return serverIpAddress;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getPrecision() {
        return precision.value;
    }

    public void setPrecision(int precision) {
        this.precision = Precision.init(precision);
    }

    public void setOffset(int i) {
        this.offset = i;
    }

    public long getOffset() {
        return offset;
    }

    public boolean equals(Object obj) {

        if (obj instanceof Synchronism) {

            Synchronism sync = (Synchronism) obj;
            return this.clientIp.equals(sync.clientIp)
                    && this.serverIp.equals(sync.serverIp)
                    && (this.port == sync.port);
        }
        return false;
    }
}
